package com.qingfeng.medical.job.order;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.qingfeng.medical.base.handler.GeneralAuthException;
import com.qingfeng.medical.base.utils.EmailUtils;
import com.qingfeng.medical.biz.hosp.domain.entity.Schedule;
import com.qingfeng.medical.biz.hosp.service.ScheduleService;
import com.qingfeng.medical.biz.information.domain.entity.UserInfo;
import com.qingfeng.medical.biz.information.service.UserInfoService;
import com.qingfeng.medical.biz.message.domain.dto.NewsNotifySaveDTO;
import com.qingfeng.medical.biz.message.domain.entity.NewsNotify;
import com.qingfeng.medical.biz.message.domain.enums.IsSeeEnum;
import com.qingfeng.medical.biz.message.domain.enums.UserTypeEnum;
import com.qingfeng.medical.biz.message.service.NewsNotifyService;
import com.qingfeng.medical.biz.order.domain.entity.OrderInfo;
import com.qingfeng.medical.biz.order.domain.entity.VisitRecord;
import com.qingfeng.medical.biz.order.domain.enums.OrderStatusEnum;
import com.qingfeng.medical.biz.order.domain.enums.VisitStatusEnum;
import com.qingfeng.medical.biz.order.service.OrderInfoService;
import com.qingfeng.medical.biz.order.service.VisitRecordService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 清风学Java
 * @version 1.0.0
 * @date 2023/5/15
 */
@Component
@Slf4j
public class OrderInfoManagementHandler {

    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private NewsNotifyService newsNotifyService;
    @Autowired
    private ScheduleService scheduleService;
    @Autowired
    private VisitRecordService visitRecordService;
    @Autowired
    private EmailUtils emailUtils;


    /**
     * 检测超时未支付订单，自动取消预约
     * <p>
     * 订单超过两个小时
     *
     * @return
     */
    @Transactional(rollbackFor = GeneralAuthException.class)
    @XxlJob(value = "orderTimeoutCancellation")
    public ReturnT orderTimeoutCancellation() {
        try {
            Calendar c = Calendar.getInstance();
            c.setTime(new Date());
            c.add(Calendar.HOUR_OF_DAY, -2);
            System.out.println(c.getTime());
            List<OrderInfo> orderInfoList = orderInfoService.list(
                    new LambdaQueryWrapper<OrderInfo>()
                            .eq(OrderInfo::getOrderStatus, OrderStatusEnum.INIT)
                            .lt(OrderInfo::getCreateTime, c.getTime())
            );

            // 处理超过两个小时还没有支付的订单
            if (CollUtil.isNotEmpty(orderInfoList)) {
                // 修改订单状态
                orderInfoList.forEach(o -> {
                    o.setOrderStatus(OrderStatusEnum.DISCARD);
                    orderInfoService.updateById(o);

                    // 修改排班预约数
                    Schedule schedule = scheduleService.getById(o.getScheduleId());
                    schedule.setAvailableNum(schedule.getAvailableNum() + 1);
                    schedule.setReservationNum(schedule.getReservationNum() - 1);
                    scheduleService.updateById(schedule);

                    // 修改就诊记录
                    VisitRecord visitRecord = visitRecordService.getOne(
                            new LambdaQueryWrapper<VisitRecord>()
                                    .eq(VisitRecord::getOrderId, o.getId())
                    );
                    visitRecord.setVisitStatus(VisitStatusEnum.UNSUBSCRIBE);
                    visitRecordService.updateById(visitRecord);


                    // 给用户发送订单自动取消的消息通知
                    UserInfo userInfo = userInfoService.getById(o.getUserId());

                    // 用户认证之后进行消息通知
                    String title = "订单"
                            + o.getOutTradeNo()
                            + "超时取消通知";
                    String content = "尊敬的用户，您在塔城地区医院预约挂号系统的订单"
                            + o.getOutTradeNo()
                            + "（"
                            + o.getDepName()
                            + "/"
                            + o.getPatientName()
                            + "-"
                            + o.getDoctorName()
                            + "（"
                            + o.getPosition()
                            + "))由于超过两小时未支付，订单已于"
                            + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"))
                            + "自动取消。";

                    // 判断账号是邮箱还是手机号
                    sendMsg(userInfo, title, content);
                });
            }

            return ReturnT.SUCCESS;
        } catch (Exception e) {
            e.printStackTrace();
            return ReturnT.FAIL;
        }
    }

    /**
     * 订单超时未支付提醒
     * 订单超过一个小数未支付提醒，只发送一次提醒
     *
     * @return
     */
    @Transactional(rollbackFor = GeneralAuthException.class)
    @XxlJob(value = "orderTimeoutAndUnpaidReminder")
    public ReturnT orderTimeoutAndUnpaidReminder() {
        try {
            Calendar c = Calendar.getInstance();
            c.setTime(new Date());
            c.add(Calendar.HOUR_OF_DAY, -1);
            System.out.println(c.getTime());
            List<OrderInfo> orderInfoList = orderInfoService.list(
                    new LambdaQueryWrapper<OrderInfo>()
                            .eq(OrderInfo::getOrderStatus, OrderStatusEnum.INIT)
                            .lt(OrderInfo::getCreateTime, c.getTime())
            );

            // 处理超过一个小时还没有支付的订单，发送一次消息提醒
            if (CollUtil.isNotEmpty(orderInfoList)) {
                // 修改订单状态
                orderInfoList.forEach(o -> {
                    // 给用户发送订单自动取消的消息通知
                    UserInfo userInfo = userInfoService.getById(o.getUserId());

                    // 用户认证之后进行消息通知
                    String title = "订单"
                            + o.getOutTradeNo()
                            + "为未支付通知";
                    String content = "尊敬的用户，您在塔城地区医院预约挂号系统的订单"
                            + o.getOutTradeNo()
                            + "（"
                            + o.getDepName()
                            + "/"
                            + o.getPatientName()
                            + "-"
                            + o.getDoctorName()
                            + "（"
                            + o.getPosition()
                            + "))由于已经超过一个小时未支付，请尽快前往系统支付，若超过两个小时将自动取消订单";

                    // 查询是否已经发送通知
                    List<NewsNotify> newsNotifyList = newsNotifyService.list(
                            new LambdaQueryWrapper<NewsNotify>()
                                    .eq(NewsNotify::getNewsTitle, title)
                    );
                    if (CollUtil.isEmpty(newsNotifyList)) {
                        // 判断账号是邮箱还是手机号
                        sendMsg(userInfo, title, content);
                    }
                });
            }

            return ReturnT.SUCCESS;
        } catch (Exception e) {
            e.printStackTrace();
            return ReturnT.FAIL;
        }
    }

    /**
     * 检测用户成功预定的订单，设置就诊提醒
     * 查询当天需要就诊的用户信息，每天早上6点提醒就诊
     *
     * @return
     */
    @Transactional(rollbackFor = GeneralAuthException.class)
    @XxlJob(value = "orderVisitReminder")
    public ReturnT orderVisitReminder() {
        List<OrderInfo> orderInfoList = orderInfoService.list(
                new LambdaQueryWrapper<OrderInfo>()
                        .eq(OrderInfo::getReserveDate, LocalDate.now())
                        .eq(OrderInfo::getOrderStatus, OrderStatusEnum.SUCCESS)
        );

        if (CollUtil.isNotEmpty(orderInfoList)) {
            orderInfoList.forEach(o -> {
                // 给用户发送订单自动取消的消息通知
                UserInfo userInfo = userInfoService.getById(o.getUserId());

                // 用户认证之后进行消息通知
                String title = "预约就诊通知";
                String content = "尊敬的用户，您在塔城地区医院预约挂号系统的订单"
                        + o.getOutTradeNo()
                        + "（"
                        + o.getDepName()
                        + "/"
                        + o.getPatientName()
                        + "-"
                        + o.getDoctorName()
                        + "（"
                        + o.getPosition()
                        + "))在今日需要取号就诊，请及时前往医院取号，医院上班时间为8:00-18:30，" +
                        "超时未就诊将视作爽约，系统不会进行退费处理，爽约六次以上，将限制预约！！！";
                sendMsg(userInfo, title, content);

            });
        }

        return ReturnT.SUCCESS;
    }


    /**
     * 查询爽约的用户
     *
     * @return
     */
    @Transactional(rollbackFor = GeneralAuthException.class)
    @XxlJob(value = "recordOfBreachOfAppointment")
    public ReturnT recordOfBreachOfAppointment(){
        List<OrderInfo> orderInfoList = orderInfoService.list(
                new LambdaQueryWrapper<OrderInfo>()
                        .eq(OrderInfo::getOrderStatus, OrderStatusEnum.SUCCESS)
                        .lt(OrderInfo::getReserveDate, LocalDate.now())
        );

        List<Long> orderIds = orderInfoList.stream()
                .map(OrderInfo::getId)
                .collect(Collectors.toList());

        List<VisitRecord> visitRecordList = visitRecordService.list(
                new LambdaQueryWrapper<VisitRecord>()
                        .in(VisitRecord::getOrderId, orderIds)
                        .eq(VisitRecord::getVisitStatus, VisitStatusEnum.INIT)
        );

        if (CollUtil.isNotEmpty(visitRecordList)) {
            visitRecordList.forEach(v-> {
                OrderInfo o = orderInfoService.getById(v.getOrderId());
                // 给用户发送订单自动取消的消息通知
                UserInfo userInfo = userInfoService.getById(o.getUserId());

                // 用户认证之后进行消息通知
                String title = "预约就诊【爽约】通知";
                String content = "尊敬的用户，您在塔城地区医院预约挂号系统的订单"
                        + o.getOutTradeNo()
                        + "（"
                        + o.getDepName()
                        + "/"
                        + o.getPatientName()
                        + "-"
                        + o.getDoctorName()
                        + "（"
                        + o.getPosition()
                        + "))未在规定时间就诊，系统已经更新为爽约记录，如果超过六次，我院将对你进行限额！！！";
                sendMsg(userInfo, title, content);
            });
        }


        return ReturnT.SUCCESS;
    }

    private void sendMsg(UserInfo userInfo, String title, String content) {
        // 判断账号是邮箱还是手机号
        if (userInfo.getAccount().contains("@")) {
            // 邮箱
            emailUtils.sendEmail(userInfo.getAccount(), title, content);
        }

        if (StrUtil.isNotBlank(userInfo.getPhone())) {
            // TODO 手机号，发送短信

        }


        // 先将消息写入数据库
        newsNotifyService.saveNewsNotify(
                NewsNotifySaveDTO.builder()
                        .userId(userInfo.getId())
                        .newsTitle(title)
                        .userType(UserTypeEnum.FRONT)
                        .newsContent(content)
                        .isSee(IsSeeEnum.IS_NOT_VIEWED)
                        .build()
        );
    }

}
